package com.delamer.facile;

import com.delamer.facile.db.DBUtilBack;
import com.delamer.facile.db.DBUtilQuest;
import com.delamer.facile.db.DBUtilSwitch;
import com.delamer.facile.obj.ObjectBack;
import com.delamer.facile.obj.ObjectQuest;
import com.delamer.facile.obj.ObjectSwitch;
import com.delamer.utils.MsgUtil;
import org.bukkit.*;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.block.data.BlockData;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.SignChangeEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.PlayerDeathEvent;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.event.player.AsyncPlayerChatEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.AnvilInventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.PlayerInventory;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.Plugin;
import org.bukkit.plugin.java.JavaPlugin;

import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Monitor implements Listener {

    private FileConfiguration config;
    private JavaPlugin plugin;

    public Monitor(FileConfiguration config, JavaPlugin plugin) {
        this.config = config;
        this.plugin = plugin;
    }

    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event) {
        event.setJoinMessage(null);
        String format = config.getString("broadcast-artistic.player-join");
        String playerName = event.getPlayer().getName();
        Bukkit.broadcastMessage(format.replace("<%PlayerName%>", playerName));
    }

    @EventHandler
    public void onPlayerQuit(PlayerQuitEvent event) {
        event.setQuitMessage(null);
        String format = config.getString("broadcast-artistic.player-quit");
        String playerName = event.getPlayer().getName();
        Bukkit.broadcastMessage(format.replace("<%PlayerName%>", playerName));
    }

    @EventHandler
    public void onEntityExplode(EntityExplodeEvent event) {
        if (null != event.getEntity())
            if (event.getEntity().getType().equals(EntityType.CREEPER)) {
                if (config.getBoolean("creeper-weaken.block-defense")) {
                    event.blockList().clear();
                    event.setYield(0);
                }
            }
    }

    @EventHandler
    public void onEntityDamageByEntity(EntityDamageByEntityEvent event) {
        if (null != event.getDamager())
            if (event.getDamager().getType().equals(EntityType.CREEPER)) {
                Double rate = config.getDouble("creeper-weaken.damage-rate");
                event.setDamage(event.getDamage() * rate);
            }
    }

    @EventHandler
    public void onAsyncPlayerChat(AsyncPlayerChatEvent event) {
        String worldName = event.getPlayer().getWorld().getName();
        if (config.contains("world-name-replace." + worldName))
            worldName = config.getString("world-name-replace." + worldName);
        String nickName = "无名";
        if (event.getPlayer().getCustomName() != null) {
            nickName = event.getPlayer().getCustomName();
        }
        String format = config.getString("broadcast-artistic.player-chat")
                .replace("<%WorldName%>", worldName)
                .replace("<%PreName%>", nickName)
                .replace("<%PlayerName%>", "%1$s")
                .replace("<%ChatContent%>", "%2$s");
        event.setFormat(format);
        try {
            ObjectSwitch object = DBUtilSwitch.getSwitch(new ObjectSwitch() {{
                setUserName(event.getPlayer().getName());
                setSwitchName("color");
            }});
            if (object != null)
                if (object.getSwitchState() > 0)
                    event.setMessage(event.getMessage().replaceAll("&", "§").replaceAll("§§", "&"));
        } catch (Exception err) {
            err.printStackTrace();
        }
        if (event.getMessage().contains("@")) {
            for (Player player : Bukkit.getOnlinePlayers()) {
                String playerAt = "@" + player.getName();
                if (event.getMessage().contains(playerAt)) {
                    event.setMessage(event.getMessage().replace(playerAt, "§b" + playerAt + "§r"));
                    player.playSound(player.getLocation(), Sound.BLOCK_NOTE_BLOCK_BELL, 1F, 0F);
                }
            }
        }
    }

    @EventHandler
    public void onSignChange(SignChangeEvent event) {
        try {
            ObjectSwitch object = DBUtilSwitch.getSwitch(new ObjectSwitch() {{
                setUserName(event.getPlayer().getName());
                setSwitchName("color");
                setSwitchState(1);
            }});
            if (object != null) {
                int length = event.getLines().length;
                for (int i = 0; i < length; i++) {
                    String str = event.getLine(i);
                    event.setLine(i, str.replaceAll("&", "§").replaceAll("§§", "&"));
                }
            }
        } catch (Exception err) {
            err.printStackTrace();
        }
    }

    @EventHandler
    public void onPrepareAnvil(PrepareAnvilEvent event) {
        AnvilInventory anvilInventory = event.getInventory();
        String name = anvilInventory.getRenameText();
        if (name != null && !name.equals("") && name.contains("&")) {
            ItemStack itemStack = anvilInventory.getItem(2);
            if (itemStack != null) {
                ItemMeta itemMeta = itemStack.getItemMeta();
                try {
                    ObjectSwitch object = DBUtilSwitch.getSwitch(new ObjectSwitch() {{
                        setUserName(event.getView().getPlayer().getName());
                        setSwitchName("color");
                        setSwitchState(1);
                    }});
                    if (object != null) {
                        itemMeta.setDisplayName(name.replaceAll("&", "§").replaceAll("§§", "&"));
                    }
                } catch (Exception err) {
                    err.printStackTrace();
                }
                itemStack.setItemMeta(itemMeta);
                event.setResult(itemStack);
            }
        }
    }

    @EventHandler
    public void onPlayerDeath(PlayerDeathEvent event) {
        try {
            ObjectSwitch object = DBUtilSwitch.getSwitch(new ObjectSwitch() {{
                setUserName(event.getEntity().getName());
                setSwitchName("keep");
            }});
            if (object != null) {
                if (object.getSwitchState() > 0) {
                    event.setKeepLevel(true);
                    event.setKeepInventory(true);
                    List<ItemStack> list = event.getDrops();
                    list.clear();
                    event.setDroppedExp(0);
                }
            }
        } catch (Exception err) {
            err.printStackTrace();
        }
        try {
            String playerName = event.getEntity().getName();
            Location location = event.getEntity().getLocation();
            ObjectBack object = DBUtilBack.getBack(playerName);
            if (object == null) {
                DBUtilBack.addBack(new ObjectBack() {{
                    setUserName(playerName);
                    setWorldName(location.getWorld().getName());
                    setLocationX(String.valueOf(((int) location.getX())));
                    setLocationY(String.valueOf(((int) location.getY())));
                    setLocationZ(String.valueOf(((int) location.getZ())));
                }});
            } else {
                DBUtilBack.setBack(new ObjectBack() {{
                    setUserName(playerName);
                    setWorldName(location.getWorld().getName());
                    setLocationX(String.valueOf(((int) location.getX())));
                    setLocationY(String.valueOf(((int) location.getY())));
                    setLocationZ(String.valueOf(((int) location.getZ())));
                }});

            }
        } catch (Exception err) {
            err.printStackTrace();
        }
    }


    @EventHandler
    public void onInventoryClick(InventoryClickEvent event) {
        ItemStack itemStack = event.getCurrentItem();
        if (itemStack != null && !itemStack.getType().name().equals("AIR")) {
            ItemMeta itemMeta = itemStack.getItemMeta();
            PersistentDataContainer persistentDataContainer = itemMeta.getPersistentDataContainer();
            Plugin pluginTemp = Bukkit.getPluginManager().getPlugin("DelamerFacile");
            if (persistentDataContainer.has(new NamespacedKey(plugin, "PluginMenuItem"), PersistentDataType.STRING)) {
                if (persistentDataContainer.has(new NamespacedKey(plugin, "QuestMenuItem"), PersistentDataType.STRING)) {
                    try {
                        Player player = (Player) event.getWhoClicked();
                        ObjectQuest object = DBUtilQuest.getQuest(player.getName(), persistentDataContainer.get(new NamespacedKey(plugin, "QuestId"), PersistentDataType.STRING));
                        if (object != null) {
                            if (Integer.valueOf(persistentDataContainer.get(new NamespacedKey(plugin, "QuestTime"), PersistentDataType.STRING)) > 0)
                                if (object.getQuestTime() >= Integer.valueOf(persistentDataContainer.get(new NamespacedKey(plugin, "QuestTime"), PersistentDataType.STRING))) {
                                    player.sendMessage(MsgUtil.err("任务提交次数已达上限，请勿重复提交"));
                                    player.closeInventory();
                                    event.setCancelled(true);
                                    return;
                                }
                        }
                        if (persistentDataContainer.has(new NamespacedKey(plugin, "QuestNeed"), PersistentDataType.STRING)) {
                            String need = persistentDataContainer.get(new NamespacedKey(plugin, "QuestNeed"), PersistentDataType.STRING);
                            List<String> questNeedList = new ArrayList<>();
                            for (String unit : need.split(","))
                                if (unit != null && unit != "")
                                    questNeedList.add(unit);
                            Map<String, Integer> questNeedMap = new HashMap<String, Integer>();
                            for (String unit : questNeedList)
                                questNeedMap.put(unit.substring(0, unit.indexOf(":")), Integer.valueOf(unit.substring(unit.indexOf(":") + 1)));
                            Map<String, Integer> questHaveMap = new HashMap<String, Integer>();
                            PlayerInventory inventory = player.getInventory();
                            for (int i = 0; i < 36; i++) {
                                ItemStack item = inventory.getItem(i);
                                if (item == null)
                                    continue;
                                String name = item.getType().name().toLowerCase();
                                if (questNeedMap.containsKey(name))
                                    if (!questHaveMap.containsKey(name))
                                        questHaveMap.put(name, i);
                            }
                            if (questNeedMap.size() > questHaveMap.size()) {
                                player.sendMessage(MsgUtil.err("任务所需道具未集齐。请集齐所需道具并保证提交道具中的同种道具被堆叠到同一格且尽量只放该一格，且所有道具均未被命名、未被损耗。"));
                                player.closeInventory();
                                event.setCancelled(true);
                                return;
                            } else {
                                for (Map.Entry entry : questHaveMap.entrySet()) {
                                    if (questNeedMap.get(entry.getKey()) > inventory.getItem(Integer.valueOf(entry.getValue().toString())).getAmount()) {
                                        player.sendMessage(MsgUtil.err("任务所需道具未集齐。请集齐所需道具并保证提交道具中的同种道具被堆叠到同一格，且所有道具均未被命名、未被损耗。"));
                                        player.closeInventory();
                                        event.setCancelled(true);
                                        return;
                                    }
                                }
                                for (Map.Entry entry : questHaveMap.entrySet()) {
                                    int slot = Integer.valueOf(entry.getValue().toString());
                                    String name = entry.getKey().toString();
                                    ItemStack item = inventory.getItem(slot);
                                    item.setAmount(item.getAmount() - questNeedMap.get(name));
                                    inventory.setItem(slot, item);
                                }
                            }
                            if (object == null) {
                                object = new ObjectQuest() {{
                                    setUserName(player.getName());
                                    setQuestId(persistentDataContainer.get(new NamespacedKey(plugin, "QuestId"), PersistentDataType.STRING));
                                }};
                                DBUtilQuest.addQuest(object);
                            } else {

                                DBUtilQuest.addQuestTime(object);
                            }
                            player.sendMessage(MsgUtil.msg("任务提交成功"));

                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        event.getWhoClicked().sendMessage(MsgUtil.err("任务提交失败，请联系管理员修复错误"));
                    }
                }

                String clickEvent = null;
                if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "AllClickEvent"), PersistentDataType.STRING)) {
                    clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "AllClickEvent"), PersistentDataType.STRING);
                } else {
                    switch (event.getClick()) {
                        case LEFT:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "LeftClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "LeftClickEvent"), PersistentDataType.STRING);
                            break;
                        case SHIFT_LEFT:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "ShiftLeftClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "ShiftLeftClickEvent"), PersistentDataType.STRING);
                            break;
                        case RIGHT:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "RightClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "RightClickEvent"), PersistentDataType.STRING);
                            break;
                        case SHIFT_RIGHT:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "ShiftRightClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "ShiftRightClickEvent"), PersistentDataType.STRING);
                            break;
                        case MIDDLE:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "MiddleClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "MiddleClickEvent"), PersistentDataType.STRING);
                            break;
                        case DROP:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "DropClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "DropClickEvent"), PersistentDataType.STRING);
                            break;
                        case CONTROL_DROP:
                            if (persistentDataContainer.has(new NamespacedKey(pluginTemp, "CtrlDropClickEvent"), PersistentDataType.STRING))
                                clickEvent = persistentDataContainer.get(new NamespacedKey(pluginTemp, "CtrlDropClickEvent"), PersistentDataType.STRING);
                            break;
                        default:
                            ;
                    }
                }
                if (clickEvent != null && clickEvent != "") {
                    Player player = (Player) event.getWhoClicked();
                    if (clickEvent.contains("<%PlayerName%>")) {
                        clickEvent = clickEvent.replace("<%PlayerName%>", player.getName());
                        player.closeInventory();
                        Bukkit.getServer().dispatchCommand(Bukkit.getConsoleSender(), clickEvent);
                    } else {
                        player.closeInventory();
                        player.performCommand(clickEvent);
                    }
                }
                event.setCancelled(true);
            }
        }
    }

    @EventHandler
    public void onPlayerInteract(PlayerInteractEvent event) {
        if (event.hasBlock() && event.getItem() != null && event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) {
            Material material = Material.getMaterial(config.getString("spanner.item").toUpperCase());
            if (material != null && event.getItem().getType().equals(material)) {
                Block block = event.getClickedBlock();
                String blockName = block.getType().name().toLowerCase();
                if (config.getStringList("spanner.enable").contains(blockName)) {
                    List<String> facings = new ArrayList<String>() {{
                        add("facing=down");
                        add("facing=up");
                        add("facing=west");
                        add("facing=east");
                        add("facing=south");
                        add("facing=north");
                    }};
                    BlockFace clickFace = event.getBlockFace();
                    BlockData blockDataBefore = block.getBlockData();
                    String stringOfBlockDataBefore = blockDataBefore.getAsString();
                    String stringOfBlockFacingBefore = "";
                    String stringOfBlockFacingAfter = "";
                    for (int index = 0; index < facings.size(); index++) {
                        String facing = facings.get(index);
                        if (stringOfBlockDataBefore.contains(facing)) {
                            stringOfBlockFacingBefore = facing;
                            if (event.getPlayer().isSneaking()) {
                                switch (clickFace) {
                                    case UP:
                                        stringOfBlockFacingAfter = "facing=down";
                                        break;
                                    case DOWN:
                                        stringOfBlockFacingAfter = "facing=up";
                                        break;
                                    case EAST:
                                        stringOfBlockFacingAfter = "facing=west";
                                        break;
                                    case WEST:
                                        stringOfBlockFacingAfter = "facing=east";
                                        break;
                                    case SOUTH:
                                        stringOfBlockFacingAfter = "facing=north";
                                        break;
                                    case NORTH:
                                        stringOfBlockFacingAfter = "facing=south";
                                        break;
                                    default:
                                        ;
                                }
                            } else {
                                stringOfBlockFacingAfter = "facing=" + clickFace.name().toLowerCase();
                            }
                        }
                    }
                    // 特殊处理：箱子、陷阱箱 (忽略大箱子)
                    if (blockName.equals("chest") || blockName.equals("trapped_chest")) {
                        if (!stringOfBlockDataBefore.contains("type=single")) {
                            stringOfBlockFacingAfter = stringOfBlockFacingBefore;
                        }
                    }
                    // 特殊处理：漏斗 (操作目标为顶部时改为底部)
                    if (blockName.equals("hopper")) {
                        if (stringOfBlockFacingAfter.equals("facing=up")) {
                            stringOfBlockFacingAfter = "facing=down";
                        }
                    }
                    // 特殊处理：改为旋转
                    if (config.getStringList("spanner.rotate").contains(blockName)) {
                        if (stringOfBlockFacingAfter.equals("facing=up") || stringOfBlockFacingAfter.equals("facing=down")) {
                            boolean clockwise = !event.getPlayer().isSneaking();
                            switch (stringOfBlockFacingBefore) {
                                case "facing=east":
                                    stringOfBlockFacingAfter = clockwise ? "facing=south" : "facing=north";
                                    break;
                                case "facing=south":
                                    stringOfBlockFacingAfter = clockwise ? "facing=west" : "facing=east";
                                    break;
                                case "facing=west":
                                    stringOfBlockFacingAfter = clockwise ? "facing=north" : "facing=south";
                                    break;
                                case "facing=north":
                                    stringOfBlockFacingAfter = clockwise ? "facing=east" : "facing=west";
                                    break;
                                default:
                                    ;
                            }
                        }
                    }
                    // 特殊处理：跳过顶部与底部
                    if (config.getStringList("spanner.ignore").contains(blockName)) {
                        if (stringOfBlockFacingAfter.equals("facing=up") || stringOfBlockFacingAfter.equals("facing=down")) {
                            stringOfBlockFacingAfter = stringOfBlockFacingBefore;
                        }
                    }
                    try {
                        String stringOfBlockDataAfter = stringOfBlockDataBefore.replace(stringOfBlockFacingBefore, stringOfBlockFacingAfter);
                        BlockData blockDataAfter = Bukkit.createBlockData(stringOfBlockDataAfter);
                        block.setBlockData(blockDataAfter);
                    } catch (Exception e) {
                        e.printStackTrace();
                        event.getPlayer().sendMessage(MsgUtil.err("使用扳手操作方块时出现问题，请联系管理员移除配置中对应的方块或提议开发者为该方块做特殊处理。"));
                    }
                }
                event.setCancelled(true);
            }
        }
    }
}
